Link to this headingSHA2

  • Merkle–Damgård based hash function
    • Vulnerable to Length extension attack

Full Example and rundown of the SHA256 algorithm

Link to this headingExample

import hashlib, binascii sha256hash = hashlib.sha256(b'hello').digest() print("SHA-256('hello') = ", binascii.hexlify(sha256hash)) #SHA-256('hello') = b'2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824'

Link to this headingImplementation 256

from cryptopals_lib import * class SHA2(object): def __init__(self, version=256): self.buffers = [0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19] self.round_constants = [0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2] self.output_size = 8 self.buffer_size = 32 self.__select_version(version) def __select_version(self, version): if version == 256: return elif version == 224: self.buffers = [0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4] self.output_size = 7 else: raise ValueError("Invalid SHA2 Version {}".format(self.version)) def _set_message(self, message): #Convert to bytes if not already byte_message = bytearray(message) #Get Length shifted by 8 and limit to 64bit int input_length_data = asint64(len(byte_message) << 3) #Append 0x80 to the end of the message as a end of message byte byte_message.append(0x80) #Pad the data to a multable of 64 bytes when the 8 byte input_length_data is added while len(byte_message) % (self.buffer_size * 2) != ((self.buffer_size * 2) - 8): byte_message.append(0x00) #Append the length data to the message byte_message += int_to_bytes_length(input_length_data, 8) return byte_message def _hash_message_chunk(self, chunk): temp_buffers = self.buffers[:] #Create the start of the temp chunks temp_chunks = bytes_to_intarray(chunk, (self.buffer_size //8), byte_order="big") #Generate the rest of the chunks for index in range(16, 64): temp1 = shift_rotate_right(temp_chunks[index-15], 7) ^ shift_rotate_right(temp_chunks[index-15], 18) ^ (temp_chunks[index-15] >> 3) temp2 = shift_rotate_right(temp_chunks[index-2], 17) ^ shift_rotate_right(temp_chunks[index-2], 19) ^ (temp_chunks[index-2] >> 10) temp_chunks.append(asint32(temp1 + temp2 + temp_chunks[index-16] + temp_chunks[index-7])) #First Rounds itteration for round_itteration in range(64): #print(round_itteration, temp_buffers) #Do Function F (a >>> 2) ^ (a >>> 13) ^ (a >>> 22) temp1 = shift_rotate_right(temp_buffers[0], 2) ^ shift_rotate_right(temp_buffers[0], 13) ^ shift_rotate_right(temp_buffers[0], 22) #Choose Majority #As a bit function (a & b) ^ (a & c) ^ (b & c) majority = (temp_buffers[0] & temp_buffers[1]) ^ (temp_buffers[0] & temp_buffers[2]) ^ (temp_buffers[1] & temp_buffers[2]) #Do Function G (e >>> 6) ^ (e >>> 11) ^ (e >>> 25) temp2 = shift_rotate_right(temp_buffers[4], 6) ^ shift_rotate_right(temp_buffers[4], 11) ^ shift_rotate_right(temp_buffers[4], 25) #Do Choice #As a bit function (e & f) ^ ((~e) & g) choice = (temp_buffers[4] & temp_buffers[5]) ^ ((~temp_buffers[4]) & temp_buffers[6]) #Add get new values temp1 = asint32(temp1 + majority) temp2 = asint32(temp_buffers[7] + temp2 + choice + self.round_constants[round_itteration] + temp_chunks[round_itteration]) #Swap and combind values in to the new buffer temp_buffers = [asint32(temp1 + temp2), temp_buffers[0], temp_buffers[1], temp_buffers[2], asint32(temp_buffers[3] + temp2), temp_buffers[4], temp_buffers[5], temp_buffers[6]] #Chunks are done with the round #Update the internal buffers with the new data self.buffers = [asint32(self.buffers[0] + temp_buffers[0]), asint32(self.buffers[1] + temp_buffers[1]), asint32(self.buffers[2] + temp_buffers[2]), asint32(self.buffers[3] + temp_buffers[3]), asint32(self.buffers[4] + temp_buffers[4]), asint32(self.buffers[5] + temp_buffers[5]), asint32(self.buffers[6] + temp_buffers[6]), asint32(self.buffers[7] + temp_buffers[7])] def hash(self, message): #Setup message with padding and length data byte_message = self._set_message(message) #Opperate on each of the 64 byte chunks for chunk in to_blocks(byte_message, (self.buffer_size * 2)): self._hash_message_chunk(chunk) #Convert Intagers to Byte string output = b"" for x in self.buffers[:self.output_size]: output += (x).to_bytes((self.buffer_size // 8), byteorder='big') return output def hash_digest(self, message): return self.hash(message).hex() if __name__ == '__main__': testsha256 = SHA2() testsha224 = SHA2(224) print(testsha256.hash_digest(b"")) #e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 print(testsha224.hash_digest(b"")) #d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f testsha256 = SHA2() testsha224 = SHA2(224) print(testsha256.hash_digest(b"a")) #ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb print(testsha224.hash_digest(b"a")) #abd37534c7d9a2efb9465de931cd7055ffdb8879563ae98078d6d6d5 testsha256 = SHA2() testsha224 = SHA2(224) print(testsha256.hash_digest(b"c7840924e344f6d3934999be91f1f079c759cfc1d7ebb38655b49415df9a1c67b9345d01c0c0aaacd51357f74e356d75fc7e22322637d54d43331b143e268b297eee06be41abefdd2b78cdc33a7f9372e9f4df44d0c5d3a981c7084b2cc6be181b13251f2151cc03d2b0c6d001c13105dd1d5bd7e3200696545ed7ed9c1dc2662fe34f35b8caffbb0466b129736fa4b0ad18e21297836814561cdeaba49b345b6f5e3717a322485acb01ba9af6fe085052bdd158ab930b80b0c96eb2fd28570e9c81579f304443a8c3e4c4e3c0968444acc65e000730b4399719936c7e141d40b6d721f4fa97254465a9ddf51f1e70ad340ad8cc27671fd8a28bda7ec2ce475ebf1819b448f8804c2a2df277ae613974c889a7dc0bfa42698e29e663e0d5591324221267fc5d3ff101e81afdb4f9fb4a40c025bbab9c5809bd297904e6ca3b8036cc4ead33ea28639803cac1a5a67572bbc7947254d15d8befd44e7125920ba5f6f6e87cf07e75e56ea47f3817ff35de2033652a5c9a797d44b811c6482a345d0201a3064b6dd9e6b86735c16efd34120a3adb3496fc52472175056bef762f76e93bd6e7253f4c2baaddeb7d2aa1ee187909fc842276021ce38c82ad57594eb416f80fa0804437a501b21e9f8643d6120b9c0ab5d7624e1c3354c473446757dd1c722f5703055598d16d2458b77defbab48b87ca205339e4417a4486958d96db")) #70887c409868b28117749f9a62a74b962cae287f81cba1a4bb0f48e029a93477 print(testsha224.hash_digest(b"c7840924e344f6d3934999be91f1f079c759cfc1d7ebb38655b49415df9a1c67b9345d01c0c0aaacd51357f74e356d75fc7e22322637d54d43331b143e268b297eee06be41abefdd2b78cdc33a7f9372e9f4df44d0c5d3a981c7084b2cc6be181b13251f2151cc03d2b0c6d001c13105dd1d5bd7e3200696545ed7ed9c1dc2662fe34f35b8caffbb0466b129736fa4b0ad18e21297836814561cdeaba49b345b6f5e3717a322485acb01ba9af6fe085052bdd158ab930b80b0c96eb2fd28570e9c81579f304443a8c3e4c4e3c0968444acc65e000730b4399719936c7e141d40b6d721f4fa97254465a9ddf51f1e70ad340ad8cc27671fd8a28bda7ec2ce475ebf1819b448f8804c2a2df277ae613974c889a7dc0bfa42698e29e663e0d5591324221267fc5d3ff101e81afdb4f9fb4a40c025bbab9c5809bd297904e6ca3b8036cc4ead33ea28639803cac1a5a67572bbc7947254d15d8befd44e7125920ba5f6f6e87cf07e75e56ea47f3817ff35de2033652a5c9a797d44b811c6482a345d0201a3064b6dd9e6b86735c16efd34120a3adb3496fc52472175056bef762f76e93bd6e7253f4c2baaddeb7d2aa1ee187909fc842276021ce38c82ad57594eb416f80fa0804437a501b21e9f8643d6120b9c0ab5d7624e1c3354c473446757dd1c722f5703055598d16d2458b77defbab48b87ca205339e4417a4486958d96db")) #30821b0053bbb3d4fac76e7e33ee40d3c53f8a92910a84e95dcdc8c1

Link to this headingImplementation 512

from cryptopals_lib import * class SHA512(object): def __init__(self, version=512): self.buffers = [0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1, 0x510e527fade682d1, 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179] self.round_constants = [0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, 0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, 0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694, 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65, 0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, 0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4, 0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70, 0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df, 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b, 0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30, 0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8, 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8, 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3, 0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec, 0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b, 0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, 0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b, 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c, 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817] self.output_size = 8 self.buffer_size = 64 self.__select_version(version) def __select_version(self, version): if version == 512: return elif version == 384: self.buffers = [0xcbbb9d5dc1059ed8, 0x629a292a367cd507, 0x9159015a3070dd17, 0x152fecd8f70e5939, 0x67332667ffc00b31, 0x8eb44a8768581511, 0xdb0c2e0d64f98fa7, 0x47b5481dbefa4fa4] self.output_size = 6 else: raise ValueError("Invalid SHA512 Version {}".format(self.version)) def _set_message(self, message): #Convert to bytes if not already byte_message = bytearray(message) #Get Length shifted by 8 and limit to 64bit int input_length_data = asint64(len(byte_message) << 3) #Append 0x80 to the end of the message as a end of message byte byte_message.append(0x80) #Pad the data to a multable of 64 bytes when the 8 byte input_length_data is added while len(byte_message) % (self.buffer_size * 2) != ((self.buffer_size * 2) - 8): byte_message.append(0x00) #Append the length data to the message byte_message += int_to_bytes_length(input_length_data, 8) return byte_message def _hash_message_chunk(self, chunk): temp_buffers = self.buffers[:] #Create the start of the temp chunks temp_chunks = bytes_to_intarray(chunk, (self.buffer_size //8), byte_order="big") #Generate the rest of the chunks for index in range(16, 80): temp1 = shift_rotate_right(temp_chunks[index-15], 1, self.buffer_size) ^ shift_rotate_right(temp_chunks[index-15], 8, self.buffer_size) ^ (temp_chunks[index-15] >> 7) temp2 = shift_rotate_right(temp_chunks[index-2], 19, self.buffer_size) ^ shift_rotate_right(temp_chunks[index-2], 61, self.buffer_size) ^ (temp_chunks[index-2] >> 6) temp_chunks.append(asint64(temp1 + temp2 + temp_chunks[index-16] + temp_chunks[index-7])) #First Rounds itteration for round_itteration in range(80): #print(round_itteration, temp_buffers) #Do Function F (a >>> 2) ^ (a >>> 13) ^ (a >>> 22) temp1 = shift_rotate_right(temp_buffers[0], 28, self.buffer_size) ^ shift_rotate_right(temp_buffers[0], 34, self.buffer_size) ^ shift_rotate_right(temp_buffers[0], 39, self.buffer_size) #Choose Majority #As a bit function (a & b) ^ (a & c) ^ (b & c) majority = (temp_buffers[0] & temp_buffers[1]) ^ (temp_buffers[0] & temp_buffers[2]) ^ (temp_buffers[1] & temp_buffers[2]) #Do Function G (e >>> 6) ^ (e >>> 11) ^ (e >>> 25) temp2 = shift_rotate_right(temp_buffers[4], 14, self.buffer_size) ^ shift_rotate_right(temp_buffers[4], 18, self.buffer_size) ^ shift_rotate_right(temp_buffers[4], 41, self.buffer_size) #Do Choice #As a bit function (e & f) ^ ((~e) & g) choice = (temp_buffers[4] & temp_buffers[5]) ^ ((~temp_buffers[4]) & temp_buffers[6]) #Add get new values temp1 = asint64(temp1 + majority) temp2 = asint64(temp_buffers[7] + temp2 + choice + self.round_constants[round_itteration] + temp_chunks[round_itteration]) #Swap and combind values in to the new buffer temp_buffers = [asint64(temp1 + temp2), temp_buffers[0], temp_buffers[1], temp_buffers[2], asint64(temp_buffers[3] + temp2), temp_buffers[4], temp_buffers[5], temp_buffers[6]] #Chunks are done with the round #Update the internal buffers with the new data self.buffers = [asint64(self.buffers[0] + temp_buffers[0]), asint64(self.buffers[1] + temp_buffers[1]), asint64(self.buffers[2] + temp_buffers[2]), asint64(self.buffers[3] + temp_buffers[3]), asint64(self.buffers[4] + temp_buffers[4]), asint64(self.buffers[5] + temp_buffers[5]), asint64(self.buffers[6] + temp_buffers[6]), asint64(self.buffers[7] + temp_buffers[7])] def hash(self, message): #Setup message with padding and length data byte_message = self._set_message(message) #Opperate on each of the 64 byte chunks for chunk in to_blocks(byte_message, (self.buffer_size * 2)): self._hash_message_chunk(chunk) #Convert Intagers to Byte string output = b"" for x in self.buffers[:self.output_size]: output += (x).to_bytes((self.buffer_size // 8), byteorder='big') return output def hash_digest(self, message): return self.hash(message).hex() if __name__ == '__main__': testsha512 = SHA512() testsha384 = SHA512(384) print(testsha512.hash_digest(b"")) #cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e print(testsha384.hash_digest(b"")) #38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b testsha512 = SHA512() testsha384 = SHA512(384) print(testsha512.hash_digest(b"a")) #1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75 print(testsha384.hash_digest(b"a")) #54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9cd697e85175033caa88e6d57bc35efae0b5afd3145f31 testsha512 = SHA512() testsha384 = SHA512(384) print(testsha512.hash_digest(b"c7840924e344f6d3934999be91f1f079c759cfc1d7ebb38655b49415df9a1c67b9345d01c0c0aaacd51357f74e356d75fc7e22322637d54d43331b143e268b297eee06be41abefdd2b78cdc33a7f9372e9f4df44d0c5d3a981c7084b2cc6be181b13251f2151cc03d2b0c6d001c13105dd1d5bd7e3200696545ed7ed9c1dc2662fe34f35b8caffbb0466b129736fa4b0ad18e21297836814561cdeaba49b345b6f5e3717a322485acb01ba9af6fe085052bdd158ab930b80b0c96eb2fd28570e9c81579f304443a8c3e4c4e3c0968444acc65e000730b4399719936c7e141d40b6d721f4fa97254465a9ddf51f1e70ad340ad8cc27671fd8a28bda7ec2ce475ebf1819b448f8804c2a2df277ae613974c889a7dc0bfa42698e29e663e0d5591324221267fc5d3ff101e81afdb4f9fb4a40c025bbab9c5809bd297904e6ca3b8036cc4ead33ea28639803cac1a5a67572bbc7947254d15d8befd44e7125920ba5f6f6e87cf07e75e56ea47f3817ff35de2033652a5c9a797d44b811c6482a345d0201a3064b6dd9e6b86735c16efd34120a3adb3496fc52472175056bef762f76e93bd6e7253f4c2baaddeb7d2aa1ee187909fc842276021ce38c82ad57594eb416f80fa0804437a501b21e9f8643d6120b9c0ab5d7624e1c3354c473446757dd1c722f5703055598d16d2458b77defbab48b87ca205339e4417a4486958d96db")) #23758bdea270ebde88ccb0d69dab03ac9f5d9b80943d25e8c82178568c08754fdbc3a4e3fdfbc85d6afadf4554acde9fbdc1d519cf4be91fee36e6c773a4a536 print(testsha384.hash_digest(b"c7840924e344f6d3934999be91f1f079c759cfc1d7ebb38655b49415df9a1c67b9345d01c0c0aaacd51357f74e356d75fc7e22322637d54d43331b143e268b297eee06be41abefdd2b78cdc33a7f9372e9f4df44d0c5d3a981c7084b2cc6be181b13251f2151cc03d2b0c6d001c13105dd1d5bd7e3200696545ed7ed9c1dc2662fe34f35b8caffbb0466b129736fa4b0ad18e21297836814561cdeaba49b345b6f5e3717a322485acb01ba9af6fe085052bdd158ab930b80b0c96eb2fd28570e9c81579f304443a8c3e4c4e3c0968444acc65e000730b4399719936c7e141d40b6d721f4fa97254465a9ddf51f1e70ad340ad8cc27671fd8a28bda7ec2ce475ebf1819b448f8804c2a2df277ae613974c889a7dc0bfa42698e29e663e0d5591324221267fc5d3ff101e81afdb4f9fb4a40c025bbab9c5809bd297904e6ca3b8036cc4ead33ea28639803cac1a5a67572bbc7947254d15d8befd44e7125920ba5f6f6e87cf07e75e56ea47f3817ff35de2033652a5c9a797d44b811c6482a345d0201a3064b6dd9e6b86735c16efd34120a3adb3496fc52472175056bef762f76e93bd6e7253f4c2baaddeb7d2aa1ee187909fc842276021ce38c82ad57594eb416f80fa0804437a501b21e9f8643d6120b9c0ab5d7624e1c3354c473446757dd1c722f5703055598d16d2458b77defbab48b87ca205339e4417a4486958d96db")) #8ed53db6d1d8e9661126a211d7126af49e9a505144c924b3aab01dbaa9527ab5ef7d1516d30300bdd176d8cce918152e